package org.ttitfly.workflow.engine.basic;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.ttitfly.workflow.Session;
import org.ttitfly.workflow.SessionHolder;
import org.ttitfly.workflow.engine.AbstractRunUnit;
import org.ttitfly.workflow.engine.Action;
import org.ttitfly.workflow.engine.Activity;
import org.ttitfly.workflow.engine.Process;
import org.ttitfly.workflow.engine.RunUnit;
import org.ttitfly.workflow.engine.run.ProcessInstance;
import org.ttitfly.workflow.engine.run.Task;
import org.ttitfly.workflow.exception.DuplicatRunUnitDefineException;
import org.ttitfly.workflow.exception.NoSessionConnectedException;
import org.ttitfly.workflow.exception.ProcessDefineException;
import org.ttitfly.workflow.exception.ProcessRunException;
import org.ttitfly.workflow.handler.Handler;


/**
 * 流程的基本功能实现
 * 
 * @author 潘海春
 * @version 2009-9-18
 */
public class BasicProcess extends AbstractRunUnit implements Process {

	/**
	 * 版本
	 */
	private float version;

	/**
	 * 运行单元
	 */
	private Map<String, RunUnit> units = new HashMap<String, RunUnit>();

	/**
	 * 默认启动action
	 */
	private Action defaultStartAction;

	/**
	 * actions
	 */
	private Map<String, Action> startActions = new HashMap<String, Action>();

	/**
	 * 构造函数
	 * 
	 * @param name
	 * @param version
	 * @param defaultStartAction
	 * @param startActions
	 * @param activeHandlers
	 * @param closeHandlers
	 */
	public BasicProcess(String name, float version, Action defaultStartAction,
			List<Action> startActions, List<Handler> activeHandlers,
			List<Handler> closeHandlers) {
		super(name, activeHandlers, closeHandlers);
		if (defaultStartAction == null && (startActions == null || startActions.isEmpty())) {
			throw new IllegalArgumentException("启动动作不能为空！");
		}
		this.version = version;
		this.defaultStartAction = defaultStartAction;
		if (defaultStartAction != null) {
			putAction(defaultStartAction.getName(), defaultStartAction);
		}
		if (startActions != null) {
			for (Action action : startActions) {
				putAction(action.getName(), action);
			}
		}
	}

	/**
	 * 放置运行单元
	 * 
	 * @param unit
	 */
	public void putUnit(RunUnit unit) {
		String name = unit.getName();
		if (units.containsKey(name)) {
			throw new DuplicatRunUnitDefineException(name, version, name);
		}
		units.put(name, unit);
	}

	/**
	 * 放置action
	 * 
	 * @param name
	 * @param action
	 */
	protected void putAction(String name, Action action) {
		if (this.startActions.containsKey(name)) {
			throw new ProcessDefineException("流程[" + name + "." + version
					+ "]已经存在一个名称为[" + name + "]的动作！");
		} else {
			this.startActions.put(action.getName(), action);
		}
	}

	@Override
	public float getVersion() {
		return version;
	}

	@Override
	protected int getStatus() {
		return SessionHolder.currentSession().currentProcessInstance().getStatus();
	}

	@Override
	protected void onInit() throws Exception {
		SessionHolder.currentSession().setCurrent(initProcessInstance());
	}

	/**
	 * 初始化流程实例
	 * 
	 * @return
	 */
	protected ProcessInstance initProcessInstance() {
		ProcessInstance pi = new ProcessInstance();
		pi.setCreator(SessionHolder.currentSession().getPrincipal());
		pi.setName((String) SessionHolder.currentSession().getVariable("name"));
		pi.setProcessName(getName());
		pi.setProcessVersion(getVersion());
		return pi;
	}

	@Override
	protected void setStatus(int status) {
		SessionHolder.currentSession().currentProcessInstance().setStatus(status);
	}

	@Override
	public void checkComplete() throws ProcessRunException {
		if (isComplete()) {
			close();
		}
	}

	@Override
	protected void onActive() throws Exception {
		SessionHolder.currentSession().currentProcessInstance().setActivationTime(new Date());
	}

	@Override
	protected void onClose() throws Exception {
		ProcessInstance pi = SessionHolder.currentSession().currentProcessInstance();
		pi.setCloseTime(new Date());
	}

	/**
	 * 关闭
	 * 
	 * @throws ProcessRunException
	 */
	protected void close() throws ProcessRunException {
		super.close();
		ProcessInstance pi = SessionHolder.currentSession().currentProcessInstance();
		Task parent = pi.getParent();
		if (parent != null) {
			Session session = SessionHolder.currentSession().fork();
			session.execute(parent.getProcessInstance().getId(), parent.getUnitName());
			try {
				session.close();
			} catch (NoSessionConnectedException e) {
				throw new ProcessRunException(e);
			}
		}
	}

	/**
	 * 是否完成
	 * 
	 * @return
	 */
	protected boolean isComplete() {
		List<Task> tasks = SessionHolder.currentSession().currentProcessInstance().getTasks();
		if (tasks == null || tasks.isEmpty()) {
			return false;
		}
		for (Task task : tasks) {
			if (!(CLOSED == task.getStatus())) {
				return false;
			}
		}
		return true;
	}

	@Override
	public void dispatch(String runUnitName) throws ProcessRunException {
		RunUnit unit = units.get(runUnitName);
		if (unit == null) {
			throw new ProcessRunException("没有找到名称为[" + runUnitName + "]的运行单元！");
		}
		Session session = SessionHolder.currentSession().fork();
		unit.run();
		try {
			session.close();
		} catch (NoSessionConnectedException e) {
			throw new ProcessRunException(e);
		}
	}

	@Override
	public void execute(String activityName) throws ProcessRunException {
		if (activityName == null || "".equals(activityName)) {
			throw new ProcessRunException("参数[activityName]不能为空！");
		}
		Activity activity = getActivity(activityName);
		if (activity == null) {
			throw new ProcessRunException("没有找到名称为[" + activityName + "]的活动！");
		}
		activity.execute();
	}

	@Override
	public void execute(String activityName, String actionName) throws ProcessRunException {
		if (activityName == null || "".equals(activityName)) {
			throw new ProcessRunException("参数[activityName]不能为空！");
		}
		Activity activity = getActivity(activityName);
		if (activity == null) {
			throw new ProcessRunException("没有找到名称为[" + activityName + "]的活动！");
		}
		activity.execute(actionName);
	}

	/**
	 * 获取活动
	 * 
	 * @param name
	 * @return
	 */
	private Activity getActivity(String name) {
		return (Activity) units.get(name);
	}

	@Override
	public boolean isClosed(String activityName) {
		List<Task> tasks = SessionHolder.currentSession().currentProcessInstance().getTasks();
		if (tasks == null || tasks.isEmpty()) {
			return false;
		}
		for (Task task : tasks) {
			if (task.getUnitName().equals(activityName) && !(CLOSED == task.getStatus())) {
				return false;
			}
		}
		return true;
	}

	@Override
	public void start() throws ProcessRunException {
		if (defaultStartAction == null) {
			throw new ProcessRunException("没有默认启动动作来执行！");
		}
		start(defaultStartAction);
	}

	@Override
	public void start(String actionName) throws ProcessRunException {
		if (actionName == null || "".equals(actionName)) {
			throw new ProcessRunException("参数[actionName]不能为空！");
		}
		Action action = startActions.get(actionName);
		if (action == null) {
			throw new ProcessRunException("没有找到名称为[" + actionName + "]的动作！");
		}
		start(action);
	}

	/**
	 * 执行start action
	 * 
	 * @param action
	 * @throws ProcessRunException
	 */
	protected void start(Action action) throws ProcessRunException {
		String nextUnitName = action.execute();
		if (nextUnitName == null) {
			throw new ProcessRunException("启动动作不能导向一个空的运行单元！");
		} else {
			run();
			dispatch(nextUnitName);
		}
	}

}
